package com.ydlclass.loadbalancer.impl;

import com.ydlclass.exceptions.LoadBalancerException;
import com.ydlclass.loadbalancer.AbstractLoadBalancer;
import com.ydlclass.loadbalancer.Selector;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 轮询的负载均衡策略
 */
@Slf4j
public class RoundRobinLoadBalancer extends AbstractLoadBalancer {
    
    //使用工厂方法设计模式，子类决定创建哪种Selector，解耦 Selector的创建与使用，支持扩展新算法。
    @Override
    protected Selector getSelector(List<InetSocketAddress> serviceList) {
        return new RoundRobinSelector(serviceList);
    }
      
    /**
     * 轮询策略的具体算法实现
     */
    private static class RoundRobinSelector implements Selector{
        private List<InetSocketAddress> serviceList;//可用的服务列表
        private AtomicInteger index; //定义游标指针用于轮询选择可用服务列表里面的服务，考虑多线程中的并发安全问题，使用原子类。
    
        public RoundRobinSelector(List<InetSocketAddress> serviceList) {
            this.serviceList = serviceList;
            this.index = new AtomicInteger(0);
        }
        
        
        @Override
        public InetSocketAddress getNext() {
            if(serviceList == null || serviceList.size() == 0){
                log.error("进行负载均衡选取节点时发现服务列表为空.");
                throw new LoadBalancerException();
            }
            
            InetSocketAddress address = serviceList.get(index.get());
            
            // 如果他到了最后的一个位置，重置
            if(index.get() == serviceList.size() - 1){
                index.set(0);
            } else {
                // 游标后移一位
                index.incrementAndGet();
            }
            
            return address;
        }
    }
    
}
